home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / mint / utils / stcron3.lzh / COMMAND.C < prev    next >
C/C++ Source or Header  |  1993-10-03  |  6KB  |  264 lines

  1. /* CROND & CRONTAB: (c) Kees Lemmens, Netherlands; June 1993.
  2.  
  3.     Programs for ATARI ST (running under MINT) to make it possible
  4.     to run background jobs at regular intervals.
  5.  
  6.     version 1.1: Okt 1993
  7.  
  8.     - Spawned jobs get uid and gid from user who submitted them.
  9.     - Default directory is changed to users homedir.
  10.       (again on special request by Jeroen Berger !)
  11.  
  12.     Any questions or suggestions about this program can be send to:
  13.     lemmens@dv.twi.tudelft.nl
  14. */
  15.  
  16. #include "cron.h"
  17.  
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <stdlib.h>
  21. #include <ctype.h>
  22. #include <time.h>
  23. #include <process.h>
  24. #include <signal.h>
  25. #include <pwd.h>
  26. #include <sys\wait.h>
  27.  
  28. extern void LogMsg(char *name, int pid, char *fmt,...);
  29. extern char *ux2dos(char *);
  30.  
  31. char *environ[] = {    "", NULL };
  32. /* Environment is not read by Mintshel so it's in fact useless ! */
  33.  
  34. int sspawnve(int mode,char *cmd, char *argstring, char **envp)
  35. {    char TosArgs[128] = "x";
  36.     int imode;
  37.     
  38. #ifdef DEBUG
  39.     mode = P_WAIT;
  40. #endif
  41.  
  42.     ux2dos(cmd);
  43.     ux2dos(argstring);
  44.  
  45.     strncat(TosArgs,argstring,sizeof(TosArgs) - 1);
  46.     *TosArgs = strlen(argstring);    /* first byte is strlen */
  47.  
  48.     switch(mode)
  49.     {    case P_WAIT    : imode=  0; break;
  50.         case P_NOWAIT  : imode=100; break;
  51.         case P_OVERLAY : imode=200; break;
  52.     }
  53.     
  54.     return (int)Pexec(imode, cmd, TosArgs, (void *)envp);
  55. }
  56.  
  57. void WriteMailHeader(entry *job,FILE *fp)
  58. {    time_t t;
  59.  
  60.     time(&t);
  61.     
  62.     /* first line conform mail headers under UNIX */
  63.  
  64.     fprintf(fp,"From cron %s",ctime(&t));
  65.     fprintf(fp,"To: %s\n",job->User);
  66.     fprintf(fp,"Subject: Output from %s job\n\n",
  67.         job->Type == CRON ? "cron" : "at");
  68.     fprintf(fp,"Command: %s\n\n",job->Command);
  69.  
  70.     fflush(fp);
  71. }
  72.  
  73. int StartJob(entry *job,active *ajob)
  74. {    char cmdstring[MAX_TEMPSTR];
  75.     static counter = 0;    /* for unique filenames */
  76.     struct passwd *pwent;
  77.     FILE *fp;
  78.     int  fd;
  79.  
  80. /* Use a unique filename for output. Tmpnam can't be used, as it 
  81.    also generates $ signs that can confuse the shell !!
  82. */
  83.  
  84. #ifdef DEBUG
  85.     strcpy(ajob->Output,"u:/dev/tty");
  86. #else    
  87.     sprintf(ajob->Output,SPOOLDIR "/%08.8d.crn",counter++);
  88. #endif
  89.  
  90.     strcpy(ajob->User,job->User);
  91.     sprintf(cmdstring,"-c %s; %.*s",DEFPATH,MAX_COMMAND,job->Command);
  92.  
  93.     if ((fp = fopen(ux2dos(ajob->Output),"w")) == NULL)
  94.         return EROUTP;
  95.  
  96.     WriteMailHeader(job,fp);
  97.  
  98.     /* redirect stdout and stderr */
  99.  
  100.     fd=fileno(fp);
  101.     Fforce(1,fd); Fforce(2,fd);
  102.  
  103.     {    if((ajob->Pid =(int)fork()) == 0)
  104.         {
  105.             /* must change uid & gid in a subprocess or it will
  106.                be impossible to change back to uid 0 again !
  107.             */
  108.  
  109.             if((pwent = getpwnam(job->User)) != NULL)
  110.             {    (void)setuid(pwent->pw_uid);
  111.                 (void)setgid(pwent->pw_gid);
  112.  
  113.                 Dsetpath(ux2dos(pwent->pw_dir));
  114.                 /* this assumes we're in drive u: */
  115.             }
  116.  
  117.             sspawnve(P_OVERLAY,SHELLCMD,cmdstring,environ);
  118.  
  119.             exit(1); /* just in case Pexec overlay fails */
  120.         }
  121.     }
  122.  
  123.     if(ajob->Pid < 0)
  124.     {    Fforce(1,0); Fforce(2,0);
  125.         fclose(fp);
  126.         return ERJOB;
  127.     }
  128.     ajob->Status = BUSY;
  129.  
  130.     Fforce(1,0); Fforce(2,0);
  131.     fclose(fp);
  132.     return ajob->Pid;
  133. }
  134.  
  135. void HandleExits(active ajobs[])
  136. {    int nr;
  137.     FILE *fp;
  138.     char cmdstring[MAX_COMMAND];
  139.     union
  140.     {    long l;
  141.         struct { int Pid; int ExitCode; } c;
  142.     } stat;
  143.  
  144.     /* collect all finished jobs */
  145.      
  146.     while((stat.l=Pwait3(WNOHANG,NULL)) > 0L)
  147.     {
  148.         for(nr=0;nr<MAX_SIMJOBS;nr++)
  149.         {    if(ajobs[nr].Pid == stat.c.Pid && ajobs[nr].Status == BUSY)
  150.             {
  151.                 LogMsg(PROGNAME,stat.c.Pid,"Job finished (exit=%d)",
  152.                     stat.c.ExitCode);
  153.  
  154.                 /* append exitcode to mail message */
  155.  
  156.                 if ((fp = fopen(ux2dos(ajobs[nr].Output),"a")) != NULL)
  157.                 {    fprintf(fp,"\nExit code : %d\n",stat.c.ExitCode);
  158.                     fclose(fp);
  159.                 }
  160.                 else
  161.                     LogMsg(PROGNAME,stat.c.Pid,"Can't append to output %s",
  162.                         ajobs[nr].Output);
  163.  
  164.                 ajobs[nr].Status = FINISHED;
  165.             }
  166.         }
  167.     }
  168.  
  169.     /* send output from finished jobs as mail to the user */
  170.  
  171. #ifndef DEBUG
  172.  
  173.     for(nr=0;nr<MAX_SIMJOBS;nr++)
  174.     {
  175.         if(ajobs[nr].Status != FINISHED)
  176.             continue;
  177.         
  178.         sprintf(cmdstring,"-c " MAILCMD " " MAILARG,
  179.             ajobs[nr].Output,ajobs[nr].User);
  180.  
  181.         sspawnve(P_WAIT,SHELLCMD,cmdstring,environ);
  182.  
  183.         /* and AFTER that (!!) remove the outputfile */
  184.                 
  185.         if(remove(ajobs[nr].Output) != 0)
  186.             LogMsg(PROGNAME,stat.c.Pid,"Can't remove output %s",
  187.                 ajobs[nr].Output);
  188.  
  189.         ajobs[nr].Status = FREE;    /* clear status */
  190.     }
  191. #endif
  192. }
  193.  
  194. void RemoveAtJob(entry *job)
  195. {    char atfile[MAX_FNAME];
  196.  
  197.     sprintf(atfile,"%s/%s.%03d",ATDIR,job->User,job->AtId);
  198.     if(remove(ux2dos(atfile)) < 0)
  199.         LogMsg(PROGNAME, getpid(), "Can't remove %s",atfile);
  200. }
  201.  
  202. void DoJobs(entry joblist[], int jobcount, active ajoblist[])
  203. {    int x,n,chpid,cmd;
  204.     int cronout;
  205.     char *message;
  206.  
  207.     for(x=0;x<jobcount;x++)
  208.     {
  209.         if(joblist[x].Status == START)
  210.         {
  211.             for(n=0;n<MAX_SIMJOBS && ajoblist[n].Status != FREE;n++);
  212.  
  213.             /* If no more jobs then don't clear job Status so we'll
  214.                retry next run.
  215.             */
  216.  
  217.             if(n>=MAX_SIMJOBS)
  218.             {    LogMsg(PROGNAME,getpid(),"No more active jobs \"%.10s\" (%s)",
  219.                     joblist[n].Command,joblist[n].User);
  220.                 return;
  221.             }
  222.  
  223.             chpid = StartJob(&joblist[x],&ajoblist[n]);
  224.  
  225.             switch(chpid)
  226.             {    case EROUTP:
  227.                     message="%Job \".15s\" (%s) no output";
  228.                 break;
  229.                 case ERJOB:
  230.                     message="%Job \".15s\" (%s) failed";
  231.                 break;
  232.                 default:
  233.                     joblist[x].Status = SLEEP;
  234.                     switch(joblist[x].Type)
  235.                     {    case CRON :
  236.                             message="CRON job \"%.10s\" (%s) started";
  237.                         break;
  238.                         case AT   :
  239.                             message="AT job \"%.10s\" (%s) started";
  240.  
  241.                             /* job can be removed: only one run */
  242.                             if((cronout=open(CRONPIPE,O_WRONLY)) < 0)
  243.                                 LogMsg(PROGNAME,getpid(),
  244.                                     "Internal write to pipe failed");
  245.                             else
  246.                             {    cmd = INTERNBUILD;
  247.                                 write(cronout,&cmd,1);
  248.                                 close(cronout);
  249.                             }
  250.                             RemoveAtJob(&joblist[x]);
  251.                         break;
  252.                     }
  253.                 break;
  254.             }
  255.             LogMsg(PROGNAME,chpid,message,joblist[x].Command,
  256.                 joblist[x].User);
  257.  
  258. #ifdef DEBUG
  259.             DebugPrintTimes(&joblist[x]);
  260. #endif
  261.             
  262.         }
  263.     }
  264. }